﻿using System.Reflection;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace Common.Utils
{
    public enum ProgressCommunication
    {
        None = 0x00,

        /// <summary>
        /// 本客户端内部通信(事件的内核)
        /// </summary>
        InnerCommunication = 0x01,

        /// <summary>
        /// 客户端间通信(例如手机A打手机B 不支持的)
        /// </summary>
        ClientToClient = 0x02,

        /// <summary>
        /// 客户端到服务器通信(手机A联系总部)
        /// </summary>
        ClientToServer = 0x04,

        /// <summary>
        /// 服务端到客户端的通信(例如学校广播 所有同学注意了 你注意不注意是你的事)
        /// </summary>
        ServerToClient = 0x08,
    }

    /// <summary>
    /// MessageAggregator(消息--实现发布订阅模式)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class MessageAggregator<T>
    {
        static MessageAggregator()
        {
            Type type = typeof(MessageAggregator<T>);
            Type messageType = typeof(T);

            //处理其他进程发送的消息(这个类必然可以序列化)
            if (messageType.IsSerializable)
            {
                MethodInfo methodInfo = type.GetMethod(nameof(DealMessage), BindingFlags.NonPublic | BindingFlags.Static);
                MessageAggregator.DcitMethodInfos.Add(messageType.FullName, methodInfo);
            }
        }

        private static Action<T> m_MessageAction;

        private static Dictionary<string, Action<T>> m_MessageDictionary=new Dictionary<string, Action<T>>();

        private static object m_MessageDictionaryLock = new object();

        /// <summary>
        /// 订阅消息
        /// </summary>
        /// <param name="action"></param>
        public static IDisposable Subscribe(Action<T> action)
        {
            m_MessageAction += action;
            Dispose dispose = new Dispose(() =>
            {
                m_MessageAction -= action;
            });
            return dispose;
        }

        /// <summary>
        /// 订阅消息
        /// </summary>
        /// <param name="action"></param>
        public static IDisposable Subscribe(Action<T> action, string contract)
        {
            lock (m_MessageDictionaryLock)
            {
                if (!m_MessageDictionary.ContainsKey(contract))
                {
                    m_MessageDictionary.Add(contract, action);
                }
                else
                {
                    m_MessageDictionary[contract] += action;
                }

                Dispose dispose = new Dispose(() =>
                {
                    if (m_MessageDictionary.ContainsKey(contract))
                    {
                        m_MessageDictionary[contract] -= action;
                    }
                });

                return dispose;
            }

            //lock (m_MessageDictionaryLock)
            //{
               
            //}


            
            //return MessageBus.Current.Listen<T>(contract).Subscribe(action);
        }



        /// <summary>
        /// 取消订阅
        /// </summary>
        /// <param name="action"></param>
        public static void UnSubscribe(Action<T> action)
        {
            m_MessageAction -= action;
        }

        /// <summary>
        /// 发布消息
        /// </summary>
        /// <param name="t"></param>
        /// <param name="progressCommunication"></param>
        public static void Publish(T t, ProgressCommunication progressCommunication = ProgressCommunication.InnerCommunication)
        {
            switch (progressCommunication)
            {
                case ProgressCommunication.InnerCommunication:
                    DealMessage(t);
                    break;
                case ProgressCommunication.ClientToServer:
                    //Todo 岳志峰 是否需要进程间通信待定(进程间通信之前只实现了Windows,虚拟机如何实现待定 考虑管道通信)
                    break;
            }
        }

        public static void Publish(T t, string contract)
        {
            if (!m_MessageDictionary.TryGetValue(contract, out Action<T> action))
            {
                return;
            }
            action?.Invoke(t);
            //if(Co)
            //MessageBus.Current.SendMessage(t, contract);
        }

        /// <summary>
        /// 处理接收的数据(不能删,不能重命名，虽然没有引用,通过反射访问这个方法)
        /// </summary>
        /// <param name="t"></param>
        private static void DealMessage(T t)
        {
            if (m_MessageAction != null)
            {
                m_MessageAction.Invoke(t);
            }
        }
    }

    public class MessageAggregator
    {
        /// <summary>
        /// 类的Guid和他的方法
        /// </summary>
        public static Dictionary<string, MethodInfo> DcitMethodInfos = new Dictionary<string, MethodInfo>();

        /// <summary>
        /// 利用反射执行,效率较低
        /// </summary>
        /// <param name="obj"></param>
        public static void Publish(object obj)
        {
            if (obj == null)
            {
                return;
            }

            Guid typeGuid = obj.GetType().GUID;
            if (!DcitMethodInfos.TryGetValue(obj.GetType().FullName, out MethodInfo methodInfo))
            {
                return;
            }
            methodInfo.Invoke(null, new object[1] { obj });
        }

        public static void Publish(object obj, string typeGuid)
        {
            if (obj == null)
            {
                return;
            }

            if (!DcitMethodInfos.TryGetValue(typeGuid, out MethodInfo methodInfo))
            {
                return;
            }

            //Type messageType = obj.GetType();
            //Type parenType = Type.GetTypeFromCLSID(typeGuid);
            //if (!parenType.IsAssignableFrom(messageType))
            //{
            //    return;
            //}
            methodInfo.Invoke(null, new object[1] { obj });
        }

        /// <summary>
        /// 利用反射执行,效率较低
        /// </summary>
        /// <param name="obj"></param>
        public static void Publish(object obj, Type parenType)
        {
            if (obj == null)
            {
                return;
            }


            Type messageType = obj.GetType();
            if (!parenType.IsAssignableFrom(messageType))
            {
                return;
            }

            Guid typeGuid = parenType.GUID;
            if (!DcitMethodInfos.TryGetValue(obj.GetType().FullName, out MethodInfo methodInfo))
            {
                return;
            }
            methodInfo.Invoke(null, new object[1] { obj });
        }

        public static void UnSubscribeAll()
        {
            MessageAggregator.DcitMethodInfos.Clear();
        }


    }

    public class Dispose : IDisposable
    {
        public Dispose(Action action)
        {
            Action = action;
        }

        public Action Action;

        void IDisposable.Dispose()
        {
            Action();
        }
    }

}
